<template>
  <div class="box"
    v-loading="loadingWs"
    :element-loading-text="loadingText"
    element-loading-spinner="el-icon-loading"
    element-loading-background="rgba(0, 0, 0, 0.6)"
  >
    <div class="action">
      <el-dropdown @command="handleCommand">
          <el-button type="success" icon="el-icon-edit-outline">
            操作<i class="el-icon-arrow-down el-icon--right"></i>
          </el-button>
          <el-dropdown-menu slot="dropdown">
            <el-dropdown-item icon="el-icon-upload2"  :command="{ flag: 'upload-file'}">上传文件/文件夹</el-dropdown-item>
            <el-dropdown-item icon="el-icon-folder" :command="{ flag: 'add-folder' }">新建文件夹</el-dropdown-item>
          </el-dropdown-menu>
      </el-dropdown>
      <div class="path-cnt" v-loading="loading">
        <div class="tips">当前路径:</div>
        <el-breadcrumb separator-class="el-icon-arrow-right" v-if="currentPathArr.length">
          <el-breadcrumb-item v-for="(path,index) in currentPathArr" @click.native="handleChangePath(path,index,'breadcrumb')" :key="path">
            {{ path }}
          </el-breadcrumb-item>
        </el-breadcrumb>
      </div>
    </div>
    <div class="table">
      <el-table
        v-loading="loading"
        :data="tableData"
        :max-height="clientHeightTable"
        border
        style="width: 100%">
        <el-table-column
          prop="filename"
          label="名称"
          width="260">
          <template slot-scope="scope">
            <div class="custom-name">
              <el-dropdown
                @command="handleCommandName"
                size="medium"
              >
                <span class="el-dropdown-link">
                  <i class="el-icon-more"></i>
                </span>
                <el-dropdown-menu slot="dropdown">
                  <template>
                    <el-dropdown-item
                      :command="{ flag: 'down',row:scope.row }"
                      >
                      <i class='el-icon-download' style="color:#13ce66"></i>
                      下载
                      </el-dropdown-item
                    >
                    <el-dropdown-item
                      :command="{ flag: 'rename',row:scope.row }"
                      >
                      <i class='el-icon-edit-outline' style="color:#137dce"></i>
                      重命名
                      </el-dropdown-item
                    >
                    <el-dropdown-item
                      :command="{ flag: 'delete',row:scope.row}"
                      >
                      <i class='el-icon-folder-remove' style="color:red"></i>
                      删除
                      </el-dropdown-item
                    >
                  </template>
                </el-dropdown-menu>
              </el-dropdown>
              <span class="name-info" @click="handleCdAndFileName(scope.row)">
                <i :class="scope.row.isDir ? 'el-icon-folder icon-color' : 'el-icon-document'"></i>
                {{scope.row.filename}}
              </span>
            </div>
          </template>
        </el-table-column>
        <el-table-column
          prop="size"
          label="大小">
          <template slot-scope="scope">
            <span v-if="scope.row.isDir!=true">{{scope.row.size}}</span>
          </template>
        </el-table-column>
        <el-table-column
          prop="permissions"
          label="权限">
        </el-table-column>
        <el-table-column
          prop="mTime"
          label="更新时间">
          <template  slot-scope="scope">
            <span>
              {{ new Date(scope.row.mTime).toLocaleString() }}
            </span>
          </template>
        </el-table-column>
        <el-table-column
          prop="user"
          label="用户">
        </el-table-column>
      </el-table>
    </div>
    <span class="upload-fixed">
      <el-popover
        placement="right"
        popper-class='popperClass'
        ref="popoverProcess"
        id="popoverProcess"
        trigger="click">
        <el-card class="upload-fixed_card" shadow="never">
          <span class="header">
            <span>上传/下载</span>
          </span>
          <el-table :data="processData" border>
            <el-table-column property="name" label="名称" width="100px" :show-overflow-tooltip="true">
              <template slot-scope="scope">
                <span class="name">
                  <i :class="scope.row.flag.includes('down') ? 'el-icon-download download icon-down-color' : 'el-icon-upload2 upload icon-upload-color'"></i>
                  {{ scope.row.name }}
                </span>
              </template>
            </el-table-column>
            <el-table-column property="process" label="进度"  width="160px">
              <template slot-scope="scope">
                <div class="process-box">
                  <el-progress
                    :text-inside="true"
                    :stroke-width="16"
                    :percentage="~~scope.row.process"
                    :status="scope.row.processStatus === 'FINISH' ? 'success' : scope.row.processStatus === 'ERROR' ? 'exception' : null">
                  </el-progress>
                </div>
              </template>
            </el-table-column>
            <el-table-column property="updateTime" label="时间"  width="130px"></el-table-column>
            <el-table-column property="processStatus" label="状态"  width="80px">
              <template  slot-scope="scope">
                <span>
                  {{ scope.row.processStatus === 'FINISH' ? '完成' : scope.row.processStatus === 'ERROR' ? '失败' : '进行中' }}
                </span>
              </template>
            </el-table-column>
            <el-table-column
              label="操作"
              width="100">
              <template slot-scope="scope">
                <el-button v-if="scope.row.processStatus === 'ERROR'" @click="handleClickRepeat(scope.row)" type="text" size="small">{{`重新${scope.row.flag.includes('down') ? '下载' : '上传'}`}}</el-button>
                <el-button v-if="scope.row.processStatus === 'FINISH'" @click="handleClickDel(scope.row)" type="text" size="small">删除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-card>
        <div slot="reference"><i class="el-icon-upload" :class="processData.length ? '' : 'disabled'"></i></div>
      </el-popover>
    </span>
    <upload-dialog ref="uploadDialog" @updateProcessData="updateProcessData"></upload-dialog>
    <down-dialog ref="downDialog" @updateProcessData="updateProcessData"></down-dialog>
    <rename-dialog ref="renameDialog" @updateProcessData="updateProcessData"></rename-dialog>
  </div>
</template>

<script>
import UploadDialog from './components/UploadDialog'
import DownDialog from './components/DownDialog'
import RenameDialog from './components/RenameDialog'
import { debounce,bFormatterTo } from '@/utils/util.js'
import * as apis from '@/api/fairyshell'
  export default {
    name:'UploadFile',
    components: {
      UploadDialog,
      DownDialog,
      RenameDialog
    },
    props: {
      data: {
        type: Object,
        default: () => ({
          socketURI:'',
        })
      },
    },
    data() {
      return {
        socket: '',
        loadingText: '初始化……',
        loadingWs: true,
        loading: true,
        currentPath: '/', // 当前路径
        tableData: [],
        processData: [] // 上传下载实时进度数据
      };
    },
    computed: {
      clientHeightTable () {
        return document.documentElement.clientHeight - 145
      },
      currentPathArr() {
        return !this.currentPath.length ? [] : this.currentPath.length === 1 ? [this.currentPath] : this.currentPath.split('/').map(c => !c ? '/' : c)
      },
      cId() {
        const cId = this.data.socketURI ? this.data.socketURI.split('ws?')[1].split('=')[1] : ''
        return cId
      }
    },
    mounted() {
      this.initSocket()
    },
    beforeDestroy() {
      //console.log('beforeDestroy')
      this.socket && this.socket.close();
      this.$refs.popoverProcess.doClose()
      this.processData = []
    },
    methods: {
      init() {
        this.loading = true
        apis.sftpCurrentInfo({cId:this.cId}).then(res => {
          if(res.data && res.data.path){
            this.currentPath = res.data.path
            this.tableData = res.data.fileInfos.map(item => {
              if(item.size) {
                item.size = bFormatterTo(item.size)
              }
              return item
            })
          }
        }).catch(res => {
          this.$notify.error({
            title: '错误',
            message: (res.data && res.data.msg) || res.msg
          })
        })
        .finally(() => {
          this.loading = false
        })
      },
      initSocket() {
        // 2.webSocket初始化
        if (this.data.socketURI === '') return;
        this.socket = new WebSocket(this.data.socketURI);
        this.socketOnOpen()
        this.socketOnMessage()
        this.socketOnClose()
        this.socketOnError()
      },
      handleCdAndFileName: debounce(function (row) {
        if(row.isDir){
          // cd path
          const path = this.currentPath.length ? this.currentPath.length === 1 ? `/${row.filename}` : `${this.currentPath}/${row.filename}` : '/'
          this.handleChangePath(path)
        }else {
          // down
          this.$refs.downDialog.init({...row,cId:this.cId,destPath: this.currentPath,processData:this.processData})
        }
      }, 500),
      // 切换上传下载路径
      handleChangePath (path,index, breadcrumb) {
        let newPath = path
        if(breadcrumb){
          const arr = this.currentPathArr.slice(0, index + 1).map(item => {

            if(item.includes('/')&&path!="/"){
              item = ''
            }

            return item
          })
          newPath = arr.join('/')
        }
        this.promiseChangePath(newPath)
      },
      handleCommand(data) {
        this.$refs.uploadDialog.init({...data,cId:this.cId,destPath: this.currentPath,processData:this.processData})
      },
      // 移动路径
      promiseChangePath (path) {
        this.loading = true
        apis.sftpCd({cId:this.cId,path}).then(res => {
          if(res.data && res.data.path){
            this.currentPath = res.data.path
            //this.tableData = res.data.fileInfos
            this.tableData = res.data.fileInfos.map(item => {
              if(item.size) {
                item.size = bFormatterTo(item.size)
              }
              return item
            })
          }else{
            this.$message({
              type: 'error',
              message: res.msg
            })
          }
        }).catch(res => {
          this.$notify.error({
            title: '错误',
            message: (res.data && res.data.msg) || res.msg
          })
        })
        .finally(() => {
          this.loading = false
        })
      },
      handleCommandName(data) {
        switch (data.flag) {
          // 下载
          case 'down':
          this.$refs.downDialog.init({flag:data.flag,...data.row,cId:this.cId,destPath: this.currentPath,processData:this.processData})
            break
          case 'rename':
            this.$refs.renameDialog.init({flag:data.flag,...data.row,cId:this.cId,destPath: this.currentPath,processData:this.processData})
            break
          case 'delete':
          this.deleteFn(data.row)
            break
        }
      },
      updateProcessData (row) {

        switch(row.flag){
          //  上传
          case 'upload-file':
            const index = row.srcPath.lastIndexOf('/') + 1
            const name = row.srcPath.substring(index)
            this.processData.push({...row,name,updateTime: new Date().toLocaleString(),process: 0})
            break
             //  新建文件夹
          case 'add-folder':
            this.currentPath = row.currentPath
            this.tableData = row.tableData
            break
             //  重命名
          case 'rename':
            this.currentPath = row.currentPath
            this.tableData = row.tableData
            break
          //  下载 'down-dir' || 'down-file'
          default:
            const _index = row.filename.lastIndexOf('/') + 1
            const _name = row.filename.substring(_index)
            this.processData.push({...row,name:_name,updateTime: new Date().toLocaleString(),process: 0 })
            break
        }
        (row.flag.includes('upload') || row.flag.includes('down')) && this.$refs.popoverProcess.doShow()
      },
      handleClickRepeat (row) {
        // repeat
        row.flag.includes('upload') && this.uploadRepeat(row)
        row.flag.includes('down') && this.downRepeat(row)
      },
      // 下载 => repeat
      downRepeat(row){
        apis
          .sftpDownload({
            cId:row.cId,
            destPath:row.srcPath,
            key:row.key,
            srcPath:row.destPath,
          })
          .then((res) => {
            if(res.data){
              this.processData = this.processData.filter(item => item.key !== row.key)
              this.updateProcessData({...row,key: res.data,flag:row.flag})
              this.$message({
                type: 'success',
                message: res.msg
              })
            }else{
              this.$message({
                type: 'error',
                message: res.msg
              })
            }
          })
      },
      // 上传 => repeat
      uploadRepeat(row) {
        apis
          .sftpUpload({
            cId:row.cId,
            destPath:row.destPath,
            key:row.key,
            srcPath:row.srcPath,
          })
          .then((res) => {
            if(res.data){
              this.processData = this.processData.filter(item => item.key !== row.key)
              this.updateProcessData({...row,key: res.data,flag:row.flag})
              this.$message({
                type: 'success',
                message: res.msg
              })
            }else{
              this.$message({
                type: 'error',
                message: res.msg
              })
            }
          })
      },
      handleClickDel (row) {
        // del
        this.processData = this.processData.filter(item => item.key !== row.key)
      },
      // 执行删除分组/文件
      deleteFn(data) {
        this.$confirm(`是否确认删除?`, '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          dangerouslyUseHTMLString: true,
          type: 'warning'
        })
          .then(() => {
            apis
              .sftpDel({
                cId: this.cId,
                delName: data.filename,
                isDir: data.isDir
              })
              .then((res) => {
                this.$message({
                  type: 'success',
                  message: '删除成功!'
                })
                if(res.data && res.data.path){
                  this.currentPath = res.data.path
                  this.tableData = res.data.fileInfos
                }
                // 更新
                // this.promiseChangePath()
              })
              .catch(res => {
                this.$notify.error({
                  title: '删除失败',
                  message: (res.data && res.data.mesg) || res.mesg
                })
              })
              .finally(() => {})
          })
          .catch(() => {})
          .finally(() => {})
      },
      socketOnMessage () {
        this.socket.onmessage = (e) => {
          const data = JSON.parse(e.data);
          switch(data.type){
            case 'Status':
              const sshStatus = JSON.parse(data.data).sshStatus
              const msg = JSON.parse(data.data).msg
              this.loadingText = msg
              if(sshStatus === 'CONNECTED'){
                // 成功
                this.loadingWs = false
                this.init()
              }else if(sshStatus === 'INIT'){
                // 初始化
                this.loadingText = '初始化……'
              }else if (sshStatus === 'CONNECTING') {
                // 连接中
                this.loadingText = `连接中……`
              }else if(sshStatus === 'ERROR') {
                this.loadingWs = true
                this.loadingText = msg
              }else if(sshStatus === 'FINISH'){
                // 失败
                this.$confirm(`连接失败，是否重连?`, '提示', {
                  confirmButtonText: '继续',
                  cancelButtonText: '取消',
                  type: 'warning'
                }).then(() => {
                  this.initSocket();
                }).catch(() => {
                  this.$message({
                    type: 'info',
                    message: '已取消重连'
                  });
                });
              }else {
                // 结束
                this.socketOnClose()
              }
              break
            case 'SftpUDInfo':
              const d = JSON.parse(data.data)
              const upStatus = d.status
              const uMsg = d.msg
              if(upStatus === 'FINISH'){
                this.init()
              }
              this.processData = JSON.parse(JSON.stringify(this.processData.map(item => {
                if(item.key === d.key && item.processStatus !== 'FINISH'){
                  item.process = d.progressSize / d.totalSize * 100
                  item.processTxt = uMsg
                  item.processStatus = upStatus
                }
                return item
              })))
              break
            default:
            break
          }
        }
      },
      socketOnOpen() {
        this.socket.onopen = () => {
          this.socket.send(JSON.stringify({
              data:JSON.stringify({dataId: ~~this.data.id.split('_')[0]}),
              type: 'SftpConn'
          }))
        }
      },
      socketOnClose() {
        this.socket.onclose = () => {}
      },
      socketOnError() {
        this.socket.onerror = () => {
          console.log('socket,onerror')
        }
      },
    }
  }
</script>

<style lang="scss" scoped>
.box{
  width:100%;
  padding:20px;
  position: relative;
  .action{
    margin-bottom:20px;
    display: flex;
    .path-cnt{
      padding-left:20px;
      display: flex;
      height: 30px;
      line-height: 30px;
      /deep/.el-breadcrumb{
        padding:0 10px;
        line-height: 30px;
        font-size: 16px;
        &__inner{
          color:#2379f1;
          cursor:pointer;
        }
      }
    }
  }
  .table{
    height: calc(100% - 56px);
    .el-table{
      .el-table__body-wrapper{
        .el-table__body{
          .el-table__row{
            .cell{
              .custom-name{
                .el-dropdown{
                  .el-dropdown-link{
                    color:#2379f1;
                  }
                }
                .name-info{
                  color:#333;
                  margin-left:16px;
                  cursor: pointer;
                }
              }
            }
          }
        }
      }
    }
  }
  .upload-fixed{
    position: absolute;
    right:10px;
    bottom:20%;
    font-size:40px;
    z-index:10;
    cursor: pointer;
    i{
      color:#46a6ff;
      &.disabled{
        color:#f4f4f5;
      }
    }
  }
}

</style>
<style lang="scss">
.el-popper{
  &.popperClass{
    padding: 20px 10px 10px 10px;
    .upload-fixed_card{
      overflow: initial;
      .el-card__body{
        position: relative;
        .header{
          position: absolute;
          left:10px;
          top:-10px;
          background-color: #fff;
          padding:0 10px;
          font-size:16px;
          color:#333;
        }
        .el-table{
          &__row{
            .cell{
              .process-box{
                display: flex;
                .el-progress{
                  flex:1
                }
              }
            }
          }
        }
      }
    }
  }
}

.icon-color{
  color:#ebc547;
}

.icon-down-color{
  color:#c11307;
}

.icon-upload-color{
  color:#129803;
}
</style>
